


/**
* @file msg.c
* @brief 进程间通信
* @author zshare
* @version v1.0
* @date 2022-03-10
* @history  
*
*	目的消息通道被关闭后即释放其所有链表
*	打开通道时即监测会有n多条消息触发
*	该不该在关闭时释放呢？
*
*	消息拥堵问题
*
*/

#include <linux/module.h>//对应内核源码中include/linux/module.h
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/init.h>	//包含了module_init和module_exit的声明
#include <linux/cdev.h>	//包含字符设备操作函数
#include <linux/fs.h>	//包含文件接口操作函数
#include <linux/uaccess.h>	//
#include <asm/atomic.h>
#include <linux/slab.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/sched/signal.h>
#include "common.h"
#include "msg.h"


ctx_st *pcontext = nil;

/** @brief chan_open
 *			打开文件
 * @param	inode[in]	- inode节点
 * @param	pfile[in]	- 文件指针
 * @return	0-成功；其它错误码
 * @discri	
 * @note	
 */
static int chan_open(struct inode *inode, struct file *pfile){
	ctx_st *pctx = nil;
	u32 index = 0;
	pctx = container_of(inode->i_cdev, ctx_st, cdev);
	index = iminor(file_inode(pfile));
	pfile->private_data = pctx->chan_item;//获取对应通道的地址
	return 0;
}

/** @brief chan_read
 *			读取文件
 * @param	pfile[in]	- 文件指针
 * @param	buffer[out]	- 读取数据缓存区
 * @param	count[in]	- 读取数量
 * @param	ppos[in]	- 偏移指针
 * @return	0-成功；其它错误码
 * @discri	
 * @note	
 */
static ssize_t chan_read(struct file *pfile, char __user *buffer, size_t count, loff_t *ppos){
	chan_item_st *pitem = pfile->private_data;
	u32 index = 0;
	u8 *pos = buffer;

	//获取该通道的结构数据
	index = iminor(file_inode(pfile));
	pitem = pitem + index * sizeof(chan_item_st);

	if(count < 1){ return 0; }

	while(!(pfile->f_flags & O_NONBLOCK)){
		if(!list_empty(&pitem->reglist) || !list_empty(&pitem->urglist)) break;
	}

	copy_msg_to_user(pitem, urg, &pos, &count);
	copy_msg_to_user(pitem, reg, &pos, &count);

	return 0;
}

/** @brief chan_write
 *			写入文件
 * @param	pfile[in]	- 文件指针
 * @param	buffer[in]	- 写入数据缓存区
 * @param	count[in]	- 写入数量
 * @param	ppos[in]	- 偏移指针
 * @return	0-成功；其它错误码
 * @discri	
 * @note	
 */
static ssize_t chan_write(struct file *pfile, const char __user *buffer, size_t count, loff_t *ppos){
	chan_item_st *pitem = pfile->private_data;
	u32 index = 0;

	//获取该通道的结构数据
	index = iminor(file_inode(pfile));
	pitem = pitem + index * sizeof(chan_item_st);
	copy_msg_from_user(pitem, buffer, &count);
	return 0;
}

/** @brief chan_poll
 *			poll方法
 * @param	pfile[in]	- 文件指针
 * @param	wait[in]	- poll的wait回调
 * @return	0-成功；其它错误码
 * @discri	
 * @note	
 */
static unsigned int chan_poll(struct file *pfile, struct poll_table_struct *wait){
	chan_item_st *pitem = pfile->private_data;
	u32 ret = 0, index = 0;
	unsigned long flags = 0;

	//获取该通道的结构数据
	index = iminor(file_inode(pfile));
	pitem = pitem + index * sizeof(chan_item_st);

	poll_wait(pfile, &pitem->wq, wait);

	spin_lock_irqsave(&pitem->lock, flags);
	if(!list_empty(&pitem->reglist) || !list_empty(&pitem->urglist)){
		ret |= POLLIN | POLLRDNORM;
	}
	ret |= POLLOUT | POLLWRNORM;
	spin_unlock_irqrestore(&pitem->lock, flags);

	return ret;
}

/** @brief chan_release
 *			关闭文件
 * @param	pfile[in]	- 文件指针
 * @param	inode[in]	- inode节点
 * @return	0-成功；其它错误码
 * @discri	
 * @note	
 */
static int chan_release(struct inode *inode, struct file *pfile){
	return 0;
}

/** @brief chan_ioctl
 *			ioctl控制消息元素
 * @param	pfile[in]	- 文件指针
 * @param	cmd[in]		- 命令字
 * @param	arg[in]		- 参数
 * @return	0-成功；其它错误码
 * @discri	
 * @note	
 */
static long chan_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg){
//	chan_item_st *pitem = pfile->private_data;


	return 0;
}

//操作函数集
static struct file_operations chan_fops =
{
	owner: 			THIS_MODULE,
	open:			chan_open,
	read:			chan_read,
	write:			chan_write,
	release:		chan_release,
	unlocked_ioctl:	chan_ioctl,
	poll:			chan_poll,
};

/** @brief chan_create
 *			创建字符设备
 * @param	
 * @param	
 * @return	0-成功；其它错误码
 * @discri	
 * @note	
 */
static int chan_create(void){
	u32 i = 0;
	ctx_st *pctx = get_ctx(ctx);

	//分配所有通道
	pctx->chan_count = CHANNEL_MAX;
	pcalloc(pctx->chan_item, 	\
			pctx->chan_count * sizeof(chan_item_st), 	\
			chan_item_st);

	for_zero_travel(i, CHANNEL_MAX){
		//创建设备节点
		pctx->chan_item[i].devno = MKDEV(MAJOR(pctx->devno), i);
		pctx->chan_item[i].minor = i;
		INIT_LIST_HEAD(&pctx->chan_item[i].reglist);//初始化普通链表
		INIT_LIST_HEAD(&pctx->chan_item[i].urglist);//初始化紧急消息链表
		spin_lock_init(&pctx->chan_item[i].lock);//初始化自旋锁
		init_waitqueue_head(&pctx->chan_item[i].wq);//初始化等待队列
		device_create(pctx->dev_class, nil, \
						pctx->chan_item[i].devno, \
						nil, "%s_%d", CHANNEL_NAME, i);
	}

	return 0;
}

/** @brief free_chan
 *			释放全局指针
 * @param	pchan	-	全局channel
 * @param	
 * @return	0-成功；其它错误码
 * @discri	
 * @note	
 */
static u32 free_chan(ctx_st *pctx)
{
	u32 i = 0;

	assert_ptr(pctx);
	for_zero_travel(i, CHANNEL_MAX){
		//todo@share释放通道上的消息节点

		//销毁设备
		device_destroy(pctx->dev_class, pctx->chan_item[i].devno);
	}
	pfree(pctx->chan_item);
	cdev_del(&(pctx->cdev));
	unregister_chrdev_region(pctx->devno, CHANNEL_MAX); 
	class_destroy(pctx->dev_class);
	pfree(pctx);
	return 0;
}

/** @brief msg_init
 *			模块初始化函数
 * @param	
 * @param	
 * @return	0-成功；其它错误码
 * @discri	
 * @note	
 */
static int __init msg_init(void){
	u32 ret = 0;
	ctx_st *pctx = nil;
	
	//申请一个全局pctx
	pcalloc(pctx, sizeof(ctx_st), ctx_st);
	//申请一个字符设备
	ret = alloc_chrdev_region(&pctx->devno, 0, CHANNEL_MAX, CHANNEL_NAME);
	if(ret != 0){ pfree(pctx); pctx = nil; return ret; } //释放pctx

	do{
		//初始化
		cdev_init(&pctx->cdev, &chan_fops);
				
		//添加到内核
		ret = cdev_add(&pctx->cdev, pctx->devno, CHANNEL_MAX);
		if(ret < 0){ cdev_del(&pctx->cdev); break; }

		pctx->dev_class = class_create(THIS_MODULE, CHANNEL_NAME);
		if(IS_ERR(pctx->dev_class)){
			kernel_print(KERN_ERR "Unable create sysfs class for demo\n");
			ret = PTR_ERR(pctx->dev_class);
			break;
		}
		get_ctx(ctx) = pctx;
		//将所有字符设备创建出来
		chan_create();
		return 0;
	}while(0);

	unregister_chrdev_region(pctx->devno, CHANNEL_MAX); 
	pfree(pctx);
	get_ctx(ctx) = pctx = nil;

	return -1;
}

/** @brief msg_exit
 *			模块卸载函数
 * @param	
 * @param	
 * @return	0-成功；其它错误码
 * @discri	
 * @note	
 */
static void __exit msg_exit(void){
	ctx_st *pctx = get_ctx(ctx);

	free_chan(pctx);
	get_ctx(ctx) = pctx = nil;
}


module_init(msg_init);
module_exit(msg_exit);

MODULE_LICENSE("GPL");//软件代码接受的许可协议General Public License
MODULE_AUTHOR("Share");//声明作者
MODULE_DESCRIPTION("msg module");//模块简单的描述
MODULE_VERSION(VERSION);//模块版本
MODULE_ALIAS("msg");//模块在用户空间的别名

















